package net.fornwall.eclipsecoder.arena;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;

/**
 * An AWTEventListener which watches for contestapplet popups and closes them.
 */
public class DialogCloser implements AWTEventListener {

	private static final DialogCloser instance = new DialogCloser();

	private DialogCloser() {
		// singleton - prevent instantiation
	}

	/**
	 * Return a button with the text "Yes" or "Ja" contained within the
	 * specified container.
	 * 
	 * @param container
	 *            The container which is searched for the button.
	 * @return A button if one is found, null otherwise.
	 */
	private static JButton findYesButton(Container container) {
		Component[] components = container.getComponents();
		for (int i = 0; i < components.length; i++) {
			if (components[i] instanceof JButton) {
				JButton button = (JButton) components[i];
				if (button.getText().equals("Yes")
						|| button.getText().equals("Ja")
						|| button.getText().equalsIgnoreCase("ok")) {
					return (JButton) components[i];
				}
			} else if (components[i] instanceof Container) {
				JButton result = findYesButton((Container) components[i]);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

	// parse out the message in popup dialogs
	private static String internalText(Container container) {
		String text = "";

		for (Component subComponent : container.getComponents()) {
			if (subComponent instanceof Container) {
				text += internalText((Container) subComponent);
			}
			if (subComponent instanceof JOptionPane) {
				text += ((JOptionPane) subComponent).getMessage();
			}
		}

		return text;
	}

	private static volatile boolean isRunning = false;

	/**
	 * Low-level window notifications.
	 */
	public void eventDispatched(AWTEvent event) {
		if (event.getSource() instanceof JDialog) {
			JDialog d = (JDialog) event.getSource();

			if (d.getTitle().equals("Warning") && d.isVisible()) {
				JButton yesButton = findYesButton(d);
				if (yesButton != null) {
					yesButton.doClick();
				}
			}

			EclipseCoderEntryPoint entryPoint = EclipseCoderEntryPoint
					.getInstance();

			if (event.getID() == WindowEvent.WINDOW_OPENED
					&& d.getTitle().equals("Compile Result") && d.isVisible()) {
				if (isCompileOk(d)) {
					entryPoint
							.appendLogMessage("Compilation was successful - submitting solution...");
					// Compiling is done on the server - now press yes and
					// submit
					JButton yesButton = findYesButton(d);
					if (yesButton != null) {
						yesButton.doClick();

					}

					entryPoint.pressSubmitButton();
				}
			}

			if (event.getID() == WindowEvent.WINDOW_OPENED
					&& d.getTitle().equals("Submission Results")
					&& d.isVisible()) {
				// "Submission was successful for xxx.xx points"
				entryPoint.appendLogMessage(internalText(d));
			}
		}
	}

	/**
	 * Check if the dialog shows that the compile went ok or not. At present
	 * this method checks this by using that a JTextArea is shown inside the
	 * JDialog if there was a compile error, and assumes all went well if no
	 * such text area can be found.
	 * 
	 * @param container
	 *            The JDialog to be checked if represents a "Compile ok" dialog.
	 * @return Whether the compile on the TopCoder server went ok.
	 */
	private boolean isCompileOk(Container container) {
		Component[] components = container.getComponents();

		for (int i = 0; i < components.length; i++) {
			if (components[i] instanceof JTextArea) {
				return false;
			} else if (components[i] instanceof Container) {
				if (!isCompileOk((Container) components[i])) {
					return false;
				}
			}
		}
		return true;
	}

	public static void start() {
		try {
			if (isRunning) {
				System.out.println("SubmitListener is already listening");
			} else {
				isRunning = true;
				Toolkit.getDefaultToolkit().addAWTEventListener(instance,
						AWTEvent.WINDOW_EVENT_MASK);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void stop() {
		if (isRunning) {
			isRunning = false;
			Toolkit.getDefaultToolkit().removeAWTEventListener(instance);
		}
	}

}